package com.aplikata.evok.service;

import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.primefaces.model.DefaultScheduleEvent;
import org.primefaces.model.ScheduleEvent;
import org.springframework.stereotype.Service;

import com.aplikata.bo.User;
import com.aplikata.bo.UserEvent;
import com.aplikata.bo.UserReference;
import com.aplikata.constants.ConstantsMsg;
import com.aplikata.evok.bo.DoctorSchedule;
import com.aplikata.evok.bo.DomainPatient;
import com.aplikata.evok.bo.Patient;
import com.aplikata.evok.bo.PatientTherapy;
import com.aplikata.evok.constants.EvokConstants;
import com.aplikata.exception.CustomException;
import com.aplikata.service.UserEventServiceImpl;
import com.aplikata.util.FacesUtil;
import com.aplikata.util.StringUtil;
import com.aplikata.util.YunDateUtil;

/**
 * @ClassName: EvokDoctorServiceImpl
 * @Description: TODO
 * @author Huyun
 * @date Sep 6, 2012 12:44:22 PM
 */

@Service("evokDoctorService")
public class EvokDoctorServiceImpl extends UserEventServiceImpl implements EvokDoctorService {
	private static Log log;
	static {
		log = LogFactory.getLog(EvokDoctorServiceImpl.class);
	}

	@SuppressWarnings("unchecked")
	@Override
	public List<Object[]> getPatientTherapyListForCanlendar(Long domainPatientId) {
		String sql = "SELECT t.start_date, group_concat(et.name separator ' | '), t.status, t.id "
				+ " FROM evk_patient_therapy t,  evk_patient_therapy_category c, evk_therapy et"
				+ " WHERE t.domain_patient_id = " + domainPatientId
				+ " and c.patient_therapy_id = t.id and c.therapy_id = et.id" + " AND t.creator = "
				+ FacesUtil.getUserFromSession().getId() + " AND t.status < "
				+ EvokConstants.PATIENT_THERAPY_STATUS_FINISH + " GROUP BY t.id ORDER BY t.start_date DESC";

		return getPublicDao().findBySql(sql);
	}

	@Override
	public Object[] getTherapyObjForCalendar(Long patientTherapyId) {
		String sql = "SELECT t.start_date, group_concat(et.name order by et.parent_id, et.sort separator ' | '), t.status, t.id "
				+ " FROM evk_patient_therapy t, evk_patient_therapy_category c, evk_therapy et"
				+ " WHERE c.patient_therapy_id = t.id and c.therapy_id = et.id"
				+ " AND t.id = "
				+ patientTherapyId
				+ " GROUP BY t.id";

		return (Object[]) this.findSingleBySql(sql);
	}

	@SuppressWarnings("unchecked")
	@Override
	public List<DoctorSchedule> getDoctorTodayResversation(Long doctorId) {
		Date tomorrow = YunDateUtil.addDay(YunDateUtil.getDate(), 1);
		String hql = " FROM DoctorSchedule e" + " WHERE e.doctor.id = " + doctorId + " AND e.status = "
				+ EvokConstants.DOC_RESERVATION_STATUS_NORMAL + " AND e.timeFrom >= '" + YunDateUtil.formatDate() + "'"
				+ " AND e.timeFrom <= '" + YunDateUtil.formatDate(tomorrow) + "' order by e.timeFrom ";

		return getPublicDao().find(hql);
	}

	@SuppressWarnings("unchecked")
	@Override
	public List<DoctorSchedule> getDoctorResversationInCanlendar(Long doctorId, Date dateFrom, Date dateTo) {
		String sql = "SELECT {e.*} FROM evk_doctor_schedule e " + " WHERE e.doctor_id = " + doctorId
				+ " AND e.status != " + EvokConstants.DOC_RESERVATION_STATUS_CANCEL + " AND e.time_from >= '"
				+ YunDateUtil.formatDate(dateFrom) + "'" + " AND e.time_from <= '" + YunDateUtil.formatDate(dateTo)
				+ "' order by e.time_from";

		return getPublicDao().getSQLQuery(sql).addEntity("e", DoctorSchedule.class).list();
	}

	@SuppressWarnings("unchecked")
	@Override
	public List<DoctorSchedule> getDoctorResversationInCanlendar(Long[] doctorIds, Date dateFrom, Date dateTo) {
		if(doctorIds == null || doctorIds.length == 0)
			return null;
		
		String idString = StringUtil.objectArrayToStr(doctorIds, ",");
		
		String sql = "SELECT {e.*} FROM evk_doctor_schedule e " + " WHERE e.doctor_id in (" + idString + ")"
				+ " AND e.status != " + EvokConstants.DOC_RESERVATION_STATUS_CANCEL + " AND e.time_from >= '"
				+ YunDateUtil.formatDate(dateFrom) + "'" + " AND e.time_from <= '" + YunDateUtil.formatDate(dateTo)
				+ "' order by e.time_from";

		return getPublicDao().getSQLQuery(sql).addEntity("e", DoctorSchedule.class).list();
	}
	
	@Override
	public List<ScheduleEvent> findDoctorAllCalendar(Long doctorId, Date dateFrom, Date dateTo) {
		List<ScheduleEvent> newlist = new ArrayList<ScheduleEvent>();

		List<ScheduleEvent> privatelist = this.getUserEventList(doctorId, dateFrom, dateTo);
		if (privatelist != null && !privatelist.isEmpty())
			newlist.addAll(privatelist);

		List<DoctorSchedule> reslist = this.getDoctorResversationInCanlendar(doctorId, dateFrom, dateTo);

		if (reslist == null || reslist.isEmpty())
			return newlist;

		List<ScheduleEvent> rslist = new ArrayList<ScheduleEvent>();
		for (DoctorSchedule res : reslist) {
			Patient patient = res.getDomainPatient().getPatient();
			DefaultScheduleEvent temp = new DefaultScheduleEvent(patient.getSurname() + " " + patient.getName() + " - "
					+ FacesUtil.getMessage("patient_reservation_default_name") + " " + res.getContent(),
					res.getTimeFrom(), res.getTimeTo(), res);

			temp.setStyleClass("doctor_reservation");
			if (res.isPriority())
				temp.setStyleClass("doctor_reservation_priority");

			rslist.add(temp);
		}

		newlist.addAll(rslist);
		return newlist;
	}

	@Override
	public List<ScheduleEvent> findDoctorAllCalendar(Long[] doctorIds, Date dateFrom, Date dateTo) {
		List<ScheduleEvent> newlist = new ArrayList<ScheduleEvent>();

		List<ScheduleEvent> privatelist = this.getUserEventList(doctorIds, dateFrom, dateTo);
		if (privatelist != null && !privatelist.isEmpty())
			newlist.addAll(privatelist);

		List<DoctorSchedule> reslist = this.getDoctorResversationInCanlendar(doctorIds, dateFrom, dateTo);

		if (reslist == null || reslist.isEmpty())
			return newlist;

		List<ScheduleEvent> rslist = new ArrayList<ScheduleEvent>();
		for (DoctorSchedule res : reslist) {
			Patient patient = res.getDomainPatient().getPatient();
			UserReference docReference = res.getDoctor().getUserReference();
			DefaultScheduleEvent temp = new DefaultScheduleEvent(docReference.getSurname() + " " + docReference.getName() + " - "
					+ patient.getSurname() + " " + patient.getName() + " - "
					+ FacesUtil.getMessage("patient_reservation_default_name") + " " + res.getContent(),
					res.getTimeFrom(), res.getTimeTo(), res);

			temp.setStyleClass("doctor_reservation");
			if (res.isPriority())
				temp.setStyleClass("doctor_reservation_priority");

			rslist.add(temp);
		}

		newlist.addAll(rslist);
		return newlist;
	}

	@SuppressWarnings("unchecked")
	@Override
	public Object updateDoctorSchedule(User user, User doctor, Integer calendarType, UserEvent userEvent, DoctorSchedule schedule,
			Long domainPatientId, Object[] therapyObj) throws Exception {

		if (FacesUtil.isKeyNull(calendarType)) {
			throw new CustomException(ConstantsMsg.MSG_REQUIRE,
					new Object[] { FacesUtil.getMessage("oa_calendar_type") });
		}
		
		if(EvokConstants.CALENDAR_TYPE_OTHER == calendarType.intValue()){
			if(StringUtil.isStrEmpty(userEvent.getTitle())){
				throw new CustomException(ConstantsMsg.MSG_REQUIRE, new Object[] { FacesUtil.getMessage("default_remark") });
			}
			if(userEvent.getTimeFrom() == null){
				throw new CustomException(ConstantsMsg.MSG_REQUIRE, new Object[] { FacesUtil.getMessage("default_from") });
			}
			if(userEvent.getTimeTo() == null){
				throw new CustomException(ConstantsMsg.MSG_REQUIRE, new Object[] { FacesUtil.getMessage("default_to") });
			}
			return merge(userEvent);
		}else{
			if (FacesUtil.isKeyNull(domainPatientId)) {
				throw new CustomException(ConstantsMsg.MSG_REQUIRE,
						new Object[] { FacesUtil.getMessage("default_name_surname") });
			}

			if(schedule.getTimeFrom() == null){
				throw new CustomException(ConstantsMsg.MSG_REQUIRE, new Object[] { FacesUtil.getMessage("default_from") });
			}
			if(schedule.getTimeTo() == null){
				throw new CustomException(ConstantsMsg.MSG_REQUIRE, new Object[] { FacesUtil.getMessage("default_to") });
			}
		}

		DomainPatient dp = (DomainPatient) getPublicDao().get(DomainPatient.class, domainPatientId);
		schedule.setDomainPatient(dp);
		schedule.setOper(user);
		schedule.setOperTime(YunDateUtil.getDateTime());
		
		if (therapyObj != null) {
			if(!FacesUtil.isKeyNull(schedule.getId())){
				if(!schedule.getDoctor().getId().equals(doctor.getId())){
					throw new CustomException(FacesUtil.getMessage("patient_reservation_changedoctor_error"));
				}
			}
			Long tid = ((BigInteger) therapyObj[3]).longValue();
			schedule.setPatientTherapy((PatientTherapy) getPublicDao().get(PatientTherapy.class, tid));
		} else {
			schedule.setPatientTherapy(null);
		}
		schedule.setDoctor(doctor);
		return getPublicDao().merge(schedule);
	}
	
	@SuppressWarnings("unchecked")
	@Override
	public List<Object[]> getUnreadComments(Long doctorId) {
		String sql = "SELECT {t.*},{dp.*},count(c.id) as unreadComm FROM evk_patient_therapy t "
				+ " join evk_domain_patient dp on t.domain_patient_id = dp.id "
				+ " join evk_patient_therapy_comment c on t.id = c.patient_therapy_id and c.read_status = 0 and c.receiver_id = " + doctorId
				+ " where t.creator = " + doctorId + " group by t.id";

		return getPublicDao().getSQLQuery(sql).addEntity("t", PatientTherapy.class)
				.addEntity("dp", DomainPatient.class).addScalar("unreadComm", new org.hibernate.type.LongType()).list();
	}

	@SuppressWarnings("unchecked")
	@Override
	public void updateFinishTodayReservation(DoctorSchedule[] schedules) throws Exception {
		if (schedules == null || schedules.length < 1) {
			return;
		}

		for (DoctorSchedule schedule : schedules) {
			schedule.setStatus(EvokConstants.DOC_RESERVATION_STATUS_FINISH);
			getPublicDao().merge(schedule);
		}
	}

	@SuppressWarnings("unchecked")
	@Override
	public List<Object[]> getDoctorResForMobile(Long doctorId, Date qyDate) {
		String sql;
		String dateString = YunDateUtil.formatDate(qyDate);
		String privatesql = " SELECT concat(u.title, ' ', DATE_FORMAT(u.time_from, '%H:%i'), ' - ', DATE_FORMAT(u.time_to, '%H:%i')),"
				+ EvokConstants.USER_EVENT_PRIVATE
				+ ", u.id FROM _user_event u where date(u.time_from) =  date('"
				+ dateString + "') AND u.user_id = " + doctorId;

		String res = " " + FacesUtil.getMessage("patient_reservation").toLowerCase() + " ";
		String ressql = " SELECT concat(p.surname, ' ', p.name, '" + res
				+ "', s.content, ' ', DATE_FORMAT(s.time_from, '%H:%i'), ' - ', DATE_FORMAT(s.time_to, '%H:%i')), "
				+ EvokConstants.USER_EVENT_THERAPY
				+ ", s.id FROM evk_doctor_schedule s, evk_domain_patient dp,  evk_patient p "
				+ " WHERE s.domain_patient_id = dp.id and dp.patient_id = p.id and s.doctor_id = " + doctorId
				+ " and date(s.time_from) = date('" + dateString + "')";

		sql = privatesql + " union " + ressql;

		return getPublicDao().findBySql(sql);
	}
	
	@Override
	public Object[] findDoctorEvents(Long[] doctorIds, Date dateFrom, Date dateTo, int startRow, int rows){
		if(doctorIds == null || doctorIds.length == 0)
			return null;
		
		String sql = " select u.* from " 
				+ " (select 'private', ue.user_id, ue.id, CONCAT(uf.surname, ' ', uf.ime, '<br/>', ue.title) as content, " 
				+ " ue.time_from , ue.time_to FROM _user_event ue, _user_reference uf WHERE ue.user_id = uf.user_id " 
				+ " union" 
				+ " select concat('patient',ds.PRIORITY), uf.user_id, ds.id, CONCAT(uf.surname, ' ', uf.ime, '<br/>', ds.content, '<br/>', p.surname, ' ', p.name) as content," 
				+ " ds.time_from, ds.time_to FROM evk_doctor_schedule ds, _user_reference uf, evk_domain_patient dp, evk_patient p  " 
				+ " WHERE ds.doctor_id = uf.user_id and ds.domain_patient_id = dp.id and dp.patient_id=p.id) u ";
		
		String idString = StringUtil.objectArrayToStr(doctorIds, ",");
		sql += " where u.user_id in (" + idString + ")";
		if(dateFrom != null){
			sql += " and u.time_from >= '" + YunDateUtil.formatDate(dateFrom) + "'";
		}
		if(dateTo != null){
			sql += " and u.time_from <= '" + YunDateUtil.formatDate(dateTo) + "'";
		}		
		
		sql += " order by u.time_from";
		String countsql = sql.replaceAll("select u.* from", "select count(u.id) from");
		return getPublicDao().findBySql(sql, countsql, startRow, rows);
	}

	@SuppressWarnings("unchecked")
	@Override
	public void deleteDoctorSchedule(DoctorSchedule schedule, User user) throws Exception{
		if(schedule == null || FacesUtil.isKeyNull(schedule.getId()) || user == null || FacesUtil.isKeyNull(user.getId()))
			return;
		
		if(!user.getId().equals(schedule.getOper().getId())){
			throw new CustomException(FacesUtil.getMessage("patient_reservation_delete_error"));
		}
		
		getPublicDao().delete(schedule);
	}
	
	@SuppressWarnings("unchecked")
	@Override
	public User[] findDomainDoctors(Long domainId, Long deptId) {
		if (FacesUtil.isKeyNull(domainId))
			return null;

		String sql = "SELECT distinct u.* FROM _user u, _user_reference uf, _role r, _employee e " 
				+ " where u.id = uf.user_id and u.role_id=r.id and r.name like 'doc-%' and u.domain_id = " + domainId;
				
		if(!FacesUtil.isKeyNull(deptId)){
			sql += " and u.id = e.user_id and e.dept_id = " + deptId;
		}

		sql += " order by uf.surname";
		
		return (User[]) getPublicDao().getSQLQuery(sql).addEntity("u", User.class).list().toArray(new User[0]);
	}
}
